#![cfg(feature = "wasm")]

use wasm_bindgen::prelude::*;
use js_sys::Promise;
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
use tokio::runtime::Runtime;
use once_cell::sync::Lazy;
use uuid::Uuid;
use wasm_bindgen_futures;

// Global Tokio runtime for WASM environment
static RUNTIME: Lazy<Runtime> = Lazy::new(|| {
    tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .expect("Failed to create Tokio runtime for WASM")
});

// Generic message wrapper for JS/TS interoperability
#[derive(Serialize, Deserialize)]
struct GenericMessage {
    #[serde(flatten)]
    data: HashMap<String, serde_json::Value>,
}

// JS/TS Actor wrapper
#[wasm_bindgen]
pub struct JsActorRef {
    actor_type: String,
    actor_ref_id: String,
}

#[wasm_bindgen]
impl JsActorRef {
    // Send a message to the actor and get a reply
    pub fn ask(&self, message: JsValue) -> Promise {
        let actor_type = self.actor_type.clone();
        let actor_ref_id = self.actor_ref_id.clone();
        
        let future = async move {
            // This would need to be implemented to look up the actor reference
            // and convert the JsValue to an appropriate Rust message type
            let result = JsValue::from_str(&format!("Asked actor {} with message", actor_ref_id));
            Ok(result)
        };
        
        wasm_bindgen_futures::future_to_promise(future)
    }
    
    // Send a message to the actor without expecting a reply
    pub fn tell(&self, message: JsValue) -> Promise {
        let actor_type = self.actor_type.clone();
        let actor_ref_id = self.actor_ref_id.clone();
        
        let future = async move {
            // This would need to be implemented to look up the actor reference
            // and convert the JsValue to an appropriate Rust message type
            let result = JsValue::from_str(&format!("Told actor {} with message", actor_ref_id));
            Ok(result)
        };
        
        wasm_bindgen_futures::future_to_promise(future)
    }
}

// Main Kameo WASM API
#[wasm_bindgen]
pub struct KameoWasm {
    // Internal state if needed
}

#[wasm_bindgen]
impl KameoWasm {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Self {
        console_log("Initializing Kameo WASM bindings");
        Self {}
    }
    
    // Spawn a new actor from JS/TS
    pub fn spawn(&self, actor_type: String, init_data: JsValue) -> Result<JsActorRef, JsValue> {
        console_log(&format!("Spawning actor of type: {}", actor_type));
        
        // This is a simplified example - in a real implementation, we would:
        // 1. Deserialize init_data into the correct Rust actor type
        // 2. Spawn the actor using kameo::spawn
        // 3. Return a JsActorRef that wraps the real ActorRef
        
        Ok(JsActorRef {
            actor_type,
            actor_ref_id: Uuid::new_v4().to_string(),
        })
    }
    
    // Register a lookup name for an actor
    pub fn register_actor(&self, actor_ref: &JsActorRef, name: String) -> Promise {
        let actor_ref_id = actor_ref.actor_ref_id.clone();
        
        let future = async move {
            // Implementation would register the actor by name
            let result = JsValue::from_str(&format!("Registered actor {} as {}", actor_ref_id, name));
            Ok(result)
        };
        
        wasm_bindgen_futures::future_to_promise(future)
    }
    
    // Look up an actor by name
    pub fn lookup_actor(&self, actor_type: String, name: String) -> Promise {
        let future = async move {
            // Implementation would look up the actor by name
            let actor_ref = JsActorRef {
                actor_type,
                actor_ref_id: Uuid::new_v4().to_string(),
            };
            Ok(JsValue::from(actor_ref))
        };
        
        wasm_bindgen_futures::future_to_promise(future)
    }
}

// Helper function for logging to the JS console
#[wasm_bindgen]
pub fn console_log(message: &str) {
    web_sys::console::log_1(&JsValue::from_str(message));
} 